#include "Simplex.h"
//in terminal run $ g++ -std=c++11 LinProg.cpp Simplex.cpp test_main.cpp 

template<typename type>
void print_vector(vector<type> vec)
{
	for_each(vec.begin(), vec.end(), [](type value){cout<<"\t"<<value<<"\t";});
	cout<<endl;
}

void printTuple(const tuple<vector<double>, string, double> &solutionData)
{
	cout<<"The variables are : ";
	print_vector(get<0>(solutionData));
	cout<<"This solution is : "<<get<1>(solutionData)<<endl;
	cout<<"The optimal value of the objective is : "<<get<2>(solutionData)<<endl;
}

int main()
{
	//	int rows=3;
//	int cols=5;	
//	vector<vector<double> > matrix(rows, vector<double>(cols));
//	vector<vector<complex <double>>> A;	
/*
	vector<vector<double>> A;	
	vector<double> r1{5,3,1,1,0,0,0};
	vector<double> r2{-5,6,15,0,1,0,0};
	vector<double> r3{2,1,1,0,0,-1,1};
	A.push_back(r1);
	A.push_back(r2);
	A.push_back(r3);

	vector<complex <double> > C{{-50,-2},{-75,-1},{-60,-1},0,0,{0,1},0};
	vector<double > b{144,240,80};	//the zero is added to the original vector b size of b=1+num_rows_of(A)... 1 is for C
	simplex linprob;
	linprob.constraints=A;
	linprob.complex_objective=C;
	linprob.inequalityVals=b; 
	linprob.b0={0,-80};	
	//solve(linprob);	//problem is infeasible

	vector<vector<double>> A1;	
	vector<double> r11{3,-3,2,8,1,0,0};
	vector<double> r21{5,6,-4,-4,0,1,0};
	vector<double> r31{4,-2,1,3,0,0,1};
	A1.push_back(r11);
	A1.push_back(r21);
	A1.push_back(r31);

	vector<complex <double> > C1{-3,-1,-5,-4,0,0,0};
	vector<double> b1{50,40,20};	//the zero is added to the original vector b size of b=1+num_rows_of(A)... 1 is for C
	simplex linprob1;
	linprob1.constraints=A1;
	linprob1.complex_objective=C1;
	linprob1.inequalityVals=b1; 
	linprob1.b0=0;
	//solve(linprob1);	//problem is unbounded
	
	vector<vector<double>> A2;	
	vector<double> q1{1,2,1,0,0};
	vector<double> q2{3,1,0,1,0};
	vector<double> q3{0,1,0,0,1};
	A2.push_back(q1);
	A2.push_back(q2);
	A2.push_back(q3);

	vector<complex <double> > C2{-2,-3,0,0,0};
	vector<double> b2{10,15,4};	//the zero is added to the original vector b size of b=1+num_rows_of(A)... 1 is for C
	simplex linprob2;
	linprob2.constraints=A2;
	linprob2.complex_objective=C2;
	linprob2.inequalityVals=b2; 
	linprob2.b0=0;

*/
	//solve(linprob2);	//has optimal solution
	
	//auto g=std::find(C.begin(),C.end(),<0);
	//print_matrix(linprob.A);
	//cout<<check_real_less_than_zero(linprob)<<endl;
	//cout<<check_imag_less_than_zero(linprob)<<endl;
	//print_vector(linprob.C);
	//cout<<index_of_lowest_real(linprob)<<endl;
	//cout<<index_of_lowest_imag(linprob)<<endl;

	//vector<double> tester{-1,-2,-3,-6,-100};
	//int index=min_element(tester.begin(),tester.end(),min_pos_comp())-tester.begin();
	//pivot check=find_pivot(linprob);
	//cout<<"pivot: "<<check.not_found<<":"<<check.row<<","<<check.col<<endl;
	//cout<<index_of_lowest_imag(linprob)<<endl;

//	for_each(linprob.A[1].begin(),linprob.A[1].end(),[](complex<double> &value){cout<<value<<" ";});
	//for_each(linprob.A[1].begin(),linprob.A[1].end(),[](complex<double> &value){value=value+1;});
	//print_tableau(linprob);
	//complex<double>g=1;
	//g=g/3;
	//pivot y;
	//y.row=2;
	//y.col=4;
	//basis_exchange(check,linprob);
	
	//cout<<linprob.A[1][2]<<endl;
	//for_each(linprob.A[1].begin(),linprob.A[1].end(),[&linprob](double &value){cout<<(linprob.A[1][2])<<endl;value/=linprob.A[1][2];});
	//for_each(linprob.A[1].begin(),linprob.A[1].end(),[&linprob](double &value){cout<<linprob.A[1][2]<<endl;value=1;});
	//print_matrix(linprob.A);
	//print_tableau(linprob);
	
/*	vector< complex<double> > CC={-3,-5,5,{0,-1},{0,-1},0,0};
	vector<vector<double>> Ap;	
	vector<double> y1{1,0,0,0,0,0,1};
	vector<double> y2{0,2,-2,1,0,0,0};
	vector<double> y3{3,2,-2,0,1,-1,0};
	Ap.push_back(y1);
	Ap.push_back(y2);
	Ap.push_back(y3);
	vector<double> b9{4,12,18};	
	simplex checking_test;
	checking_test.complex_objective=CC;
	checking_test.constraints=Ap;
	checking_test.inequalityVals=b9;
	checking_test.b0=0;
	convert_to_identity(checking_test); 
*/

    Simplex p;
    p.setMaximum(true);
    p.setObjective( { 3, 1, 5, 4});
    vector<double> eq1 = { 3, -3, 2, 8};
    vector<double> eq2 = { 5, 6, -4, -4 };
    vector<double> eq3 = { 4, -2 , 1, 3 };

    p.setConstraints( { eq1, eq2, eq3});
    p.setInequalitySigns( { "<=", "<=", "<=" });
    p.setInequalityVals( { 50, 40, 20});
    p.setConstrainedVars( {"c","c","c","c"});

    cout << "Primal: " <<endl;
    p.printProgram(p);
    cout << "TESTING: " <<endl;
    //p.convertToSimplexForm (p);
    //tst.printProgram(tst); 
   // tst.print_tableau(tst);
    //p.solve();
    printTuple(p.solve());	

/*

	LinProg p;	
	p.setMaximum(true);
	p.setObjective( { 3, 5 });
	vector<double> eq1 = { 1, 0 };
	vector<double> eq2 = { 0, 2 };
	vector<double> eq3 = { 3, 2 };
	//vector<double> eq4 = { -2, 2, 1 };
	//vector<double> eq5 = { 3, 0, 0 };
	p.setConstraints( { eq1, eq2, eq3 });
	p.setInequalitySigns( { "<=", "<=", "<=" });
	p.setInequalityVals( { 4, 12, 18 });
	p.setConstrainedVars( {"c","c"});

	Simplex s_problem(p);
	//k_problem.convertToStandardForm();
	//k_problem.convertToStandardForm().printLinProg();	
	//k_problem.printLinProg();	
	printTuple(s_problem.solve());	
*/	
/*
    cout <<endl << "Dual: " << endl;
    Program<double> q;
    q = convertToDual(p);
    printProgram(q);
*/
    //conversion stuff
/*
    cout << "TESTING: " <<endl;
    Simplex tst;
    tst = convertToStandard (p);
    printProgram(tst); 
    print_tableau(tst);
*/


}
